#include "stdafx.h"
#include "RenderTarget.h"
#include "GraphicsManager.h"

RenderTarget::RenderTarget(void)
{

}

RenderTarget::~RenderTarget(void)
{
	if (rt)
		rt->Release();
}

RenderTarget::RenderTarget(unsigned int width, unsigned int height, DXGI_FORMAT format, ID3D11Device* device)
{
	this->width = width;
	this->height = height;

	// create a texture for the render target
	D3D11_TEXTURE2D_DESC tex_desc;
	ZeroMemory(&tex_desc, sizeof(D3D11_TEXTURE2D_DESC));

	tex_desc.ArraySize = 1;
	tex_desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
	tex_desc.Format = format;
	tex_desc.Height = height;
	tex_desc.Width = width;
	tex_desc.MipLevels = 1;
	tex_desc.Usage = D3D11_USAGE_DEFAULT;
	tex_desc.SampleDesc.Count = 1;

	ID3D11Texture2D* texture;
	if (!device)
	{
		GraphicsManager::GetInstance()->getDevice()->CreateTexture2D(&tex_desc, nullptr, &texture);

		// create a d3d11 render target
		D3D11_RENDER_TARGET_VIEW_DESC rtv_desc;
		ZeroMemory(&rtv_desc, sizeof(D3D11_RENDER_TARGET_VIEW_DESC));

		rtv_desc.Format = format;
		rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
		GraphicsManager::GetInstance()->getDevice()->CreateRenderTargetView(texture, &rtv_desc, &rt);
		// create a resource view for the render target
		D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
		ZeroMemory(&srv_desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));

		srv_desc.Format = format;
		srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		srv_desc.Texture2D.MipLevels = -1;
		GraphicsManager::GetInstance()->getDevice()->CreateShaderResourceView(texture, &srv_desc, &srv);	
	}
	else
	{
		device->CreateTexture2D(&tex_desc, nullptr, &texture);
		// create a d3d11 render target
		D3D11_RENDER_TARGET_VIEW_DESC rtv_desc;
		ZeroMemory(&rtv_desc, sizeof(D3D11_RENDER_TARGET_VIEW_DESC));

		rtv_desc.Format = format;
		rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
		device->CreateRenderTargetView(texture, &rtv_desc, &rt);
		// create a resource view for the render target		
		D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
		ZeroMemory(&srv_desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));

		srv_desc.Format = format;
		srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		srv_desc.Texture2D.MipLevels = -1;
		device->CreateShaderResourceView(texture, &srv_desc, &srv);
	}
	// release temp texture
	texture->Release();
}

RenderTarget::RenderTarget(ID3D11Texture2D* texture, ID3D11Device* device, bool makeShaderResource)
{
	if (device)
	{
		// create a d3d11 render target
		device->CreateRenderTargetView(texture, NULL, &rt);
		// create a resource view for the render target
		if (makeShaderResource)
			device->CreateShaderResourceView(texture, NULL, &srv);

		// update width and height members
		D3D11_TEXTURE2D_DESC desc;
		texture->GetDesc(&desc);

		this->width = desc.Width;
		this->height = desc.Height;
	}
	else
	{
		D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
		ZeroMemory(&srv_desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));

		// create a d3d11 render target
		GraphicsManager::GetInstance()->getDevice()->CreateRenderTargetView(texture, NULL, &rt);
		// create a resource view for the render target
		if (makeShaderResource)
			GraphicsManager::GetInstance()->getDevice()->CreateShaderResourceView(texture, NULL, &srv);

		// update width and height members
		D3D11_TEXTURE2D_DESC desc;
		texture->GetDesc(&desc);

		this->width = desc.Width;
		this->height = desc.Height;
	}
}

void RenderTarget::ApplyShaderResorce(unsigned int slot)
{
	GraphicsManager::GetInstance()->getDeviceContext()->PSSetShaderResources(slot, 1, &srv);
	this->srv_slot = slot;
}

/*virtual*/ void RenderTarget::getData(void* data, unsigned int pixelStride)
{
	GraphicsManager* pgraphics = GraphicsManager::GetInstance();

	D3D11_MAPPED_SUBRESOURCE subresource;
	ZeroMemory(&subresource, sizeof(D3D11_MAPPED_SUBRESOURCE));

	data = new char[getWidth() * getHeight()];
	pgraphics->getDeviceContext()->Map((ID3D11Resource*)rt, 0, D3D11_MAP_WRITE_DISCARD, 0, &subresource);
	memcpy(subresource.pData, data, getWidth() * getHeight() * pixelStride);
	pgraphics->getDeviceContext()->Unmap((ID3D11Resource*)rt, 0);
}

/*virtual*/ void RenderTarget::setData(void* data, unsigned int pixelStride)
{
	GraphicsManager* pGraphics = GraphicsManager::GetInstance();

	D3D11_MAPPED_SUBRESOURCE subresource;
	ZeroMemory(&subresource, sizeof(D3D11_MAPPED_SUBRESOURCE));

	pGraphics->getDeviceContext()->Map((ID3D11Resource*)rt, 0, D3D11_MAP_WRITE_DISCARD, 0, &subresource);
	memcpy(subresource.pData, data, getWidth() * getHeight() * pixelStride);
	pGraphics->getDeviceContext()->Unmap((ID3D11Resource*)rt, 0);
}

/*virtual*/ ID3D11Resource* RenderTarget::getResource(void) const
{
	return (ID3D11Resource*)rt;
}

/*virtual*/ ID3D11ShaderResourceView* RenderTarget::getSrv(void) const /*override*/
{
	return srv;
}